package com.topfox.common;

import com.topfox.misc.Misc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public final class ExceptionBuilder {
    private String responseCode;
    private StringBuilder sbMsg;
    private Class clazz;

    public ExceptionBuilder(Class clazz, String code, Object target){
        this.clazz = clazz;
        this.responseCode = code;
        this.sbMsg = new StringBuilder();

        IRestSessionHandler restSessionHandler = AppContext.getRestSessionHandler();
        AbstractRestSession restSession = null;
        if (restSessionHandler != null) {
            restSession = restSessionHandler.get();
        }


        if (restSession != null) {
            this.sbMsg.append("[");
            if (Misc.isNotNull(restSession.getAppName())){
                this.sbMsg.append("appcationName:").append(restSession.getAppName());
            }
            String sessionId =restSession.getSessionId();
            String executeId =restSession.getExecuteId();
            String userId    =restSession.getSysUserId();
            String userCode  =restSession.getSysUserCode();
            String userName  =restSession.getSysUserName();
            String userMobile=restSession.getSysUserMobile();

            if (sessionId!=null && sessionId.length()>2) {
                if (this.sbMsg.length()>1) {this.sbMsg.append(", ");}
                this.sbMsg.append("sessionId:").append(sessionId);
            }
            if (executeId!=null && executeId.length()>2) {
                if (this.sbMsg.length()>1) {this.sbMsg.append(", ");}
                this.sbMsg.append("executeId:").append(executeId);
            }
            if (userId!=null    && userId.length()>2   ) {this.sbMsg.append(", userId:").append(userId);}
            if (userCode!=null  && userCode.length()>2 ) {this.sbMsg.append(", userCode:").append(userCode);}
            if (userName!=null  && userName.length()>2 ) {this.sbMsg.append(", userName:").append(userName);}
            if (userMobile!=null&& userMobile.length()>2){this.sbMsg.append(", userMobile:").append(userMobile);}
        }
        if(target !=null ) {
            this.sbMsg.append(", class:").append(target.getClass().getName());
        }
        this.sbMsg.append("]\n\r");

    }

    public TopException text(Object... values){
        if (values==null){
            this.sbMsg.append("null");
        }
        String tempMsg;
        for (Object value : values) {
            value = value==null?"null":value;
            /////////////////////////////////////////
            //解决有两个 的问题 [appcationName:customs-dev, executeId:190319043640P600DPJ655, userId:00384]\n\r[appcationName:customs-dev, executeId:190319043640P600DPJ655, userId:00384]
            //参数值[id]不能为空！
            tempMsg = value.toString();
            int pos =tempMsg.lastIndexOf("]\n\r");
            if (pos > 0 ) {
                tempMsg = tempMsg.substring(pos + 3);
            }
            ////////////////////////////////////////
            this.sbMsg.append(tempMsg);
        }

        if (TopException.class.getName().equals(clazz.getName())) {
            return new TopException(responseCode, this.sbMsg.toString());
        }else{
            return new CommonException(responseCode, this.sbMsg.toString());
        }
    }

    public StringBuilder getMsg(){
        return this.sbMsg;
    }
    static String exceptionExcludeTrace=null;
    static List<String> list;
    public static boolean findExcludeTrace(StackTraceElement ste) {
        if (log.isDebugEnabled() || exceptionExcludeTrace==null) {
            exceptionExcludeTrace = AppContext.environment().getProperty("top.exception.exclude-trace");
            if (exceptionExcludeTrace == null) {
                exceptionExcludeTrace = "";
            }
            list=Misc.string2Array(exceptionExcludeTrace,",");
        }

        boolean ret=false;

        if (list!=null) {
            for (String findStr : list) {
                ret = ste.getClassName().contains(findStr);
                if (ret == true) {
                    break;
                }
            }
        }
        return ret;
    }

    public static void printStackTrace(Throwable e, Response response){
        List<StackTraceElement> list= new ArrayList();
        String method=null;
        Throwable out;

        if (e instanceof TopException) {
            out=e;
        }else{
            //异常处理优化
            out = TopException.newInstance(ResponseCode.ERROR).text(response.getMsg());
            StackTraceElement[] steTemp1=out.getStackTrace();
            for (int i=0;i<steTemp1.length;i++){
                if (i>5){break;}
                if (steTemp1[i].getClassName().contains("com.topfox")){
                    list.add(steTemp1[i]);
                }
            }
        }

        StackTraceElement[] steTemp2 = e.getStackTrace();
        for (StackTraceElement ste:steTemp2){
            if (findExcludeTrace(ste) ){
                continue;
            }

            list.add(ste);
            if (StringUtils.isEmpty(method)){
                method = findCauseElement(ste);
            }

//            if (ste.getClassName().contains("com.topfox.filter.ParamFilter")){
//                break;
//            }
        }

        out.setStackTrace(list.toArray(new StackTraceElement[0]));
        out.printStackTrace();

        response.setMethod(method);
    }


    public static String findCauseElement(StackTraceElement ste){
        if (ste.getClassName().startsWith("org.")
                || ste.getClassName().startsWith("java")
                || ste.getClassName().startsWith("com.topfox.common.ExceptionBuilder")
                || ste.getClassName().startsWith("com.topfox.sql.Condition") && "endWhere".equals(ste.getMethodName())
                || ste.getClassName().startsWith("com.sun")
                || ste.getClassName().startsWith("feign.")
        ) {
            //异常抛出层次优化
            return null;
        }

        StringBuilder sb=new StringBuilder();
        sb.append(ste.getClassName())
                .append(".")
                .append(ste.getMethodName())
                .append(":")
                .append(ste.getLineNumber());
        return sb.toString();
    }
}
